package com.kaifamiao.demo.d0728;

public class Student implements Cloneable{

    private String name;

    private int age;

    private String hobby;

    private int  no;

    private Boy boyFriend;

    public Student(String name, int age, String hobby){
        this.name = name;
        this.age = age;
        this.hobby = hobby;
    }

    public Student(String name, int age, String hobby, int no){
        this.name = name;
        this.age = age;
        this.hobby = hobby;
        this.no = no;
    }

    public void setBoyFriend(Boy boyFriend){
        this.boyFriend = boyFriend;
    }

    public Boy getBoyFriend(){
        return this.boyFriend;
    }

    @Override
    public String toString() {
        return "Student: name= " + this.name + ", age = " + this.age + ", hobby = " + this.hobby
                + ", boyFriend = " + boyFriend.toString();
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        // super.clone() 浅克隆
        Student clone = (Student) super.clone();
        clone.setBoyFriend((Boy) clone.boyFriend.clone());
        return clone;
    }


    /**
     * 两个 Student 对象相等
     * @param obj
     * @return
     *
     * 它是自反的：对于任何非空引用值 x，x.equals(x)都应该返回 true。
     * 它是对称的：对于任何非空引用值 x和 y，当且仅当 返回时才x.equals(y) 应该返回 true. y.equals(x)true
     * 它是可传递的：对于任何非空引用值 x、y和z，如果 x.equals(y)返回true和 y.equals(z)返回true，则 x.equals(z)应该返回true。
     * 它是一致的：对于任何非空引用值 x和y，多次调用 x.equals(y)一致返回true 或一致返回false，前提equals是没有修改对象比较中使用的信息。
     * 对于任何非空引用值x， x.equals(null)应该返回false。
     *
     *  name 一样
     *  age  一样
     *  hobby 一样
     *  no  一样
     */
    @Override
    public boolean equals(Object obj){
        if (obj == null){
            return false;
        }
        if (this == obj){
            return true;
        }

        // 强制类型转换
        Student stu = (Student)obj;

//        return this.name.equals(stu.name) && this.age == stu.age
//                && this.hobby.equals(stu.hobby) && this.no == stu.no;
        if (this.name.equals(stu.name)){
            if (this.age == stu.age){
                if (this.hobby.equals(stu.hobby)){
                    if(this.no == stu.no){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 在 Java 应用程序执行期间，只要在同一个对象上多次调用它，该hashCode方法必须始终返回相同的整数，前提equals是没有修改对象比较中使用的信息。该整数不需要从应用程序的一次执行到同一应用程序的另一次执行保持一致。
     * 如果根据方法两个对象相等equals，则对两个对象中的每一个调用该 hashCode方法必须产生相同的整数结果。
     * 不要求如果两个对象根据该方法不相等，equals则对两个对象中的每一个调用该hashCode方法必须产生不同的整数结果。但是，程序员应该意识到，为不相等的对象生成不同的整数结果可能会提高哈希表的性能。
     * @return
     *
     *  一个对象多次调用结果一致
     *  equals 为 true， hashCode 结果一样
     *  equals 为 false， hashCode 不一定一样
     *  hashCode 一样，equals 不一定为 true
     *  hashCode 不一样， equals 一定为 false
     *
     *  每个字段的 hash * 31 加起来
     */
    @Override
    public int hashCode(){
        final int h = 31;
        int result = 0;
        result += h * name.hashCode();
        result += h * age;
        result += h * hobby.hashCode();
        result += h * no;

        return result;
    }
}
